package com.tengfei.main.course.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tengfei.common.core.domain.PageQuery;
import com.tengfei.common.core.page.TableDataInfo;
import com.tengfei.common.exception.ServiceException;
import com.tengfei.common.utils.JsonUtils;
import com.tengfei.common.utils.StringUtils;
import com.tengfei.main.course.domain.*;
import com.tengfei.main.course.domain.bo.ChapterBo;
import com.tengfei.main.course.domain.bo.ChapterResBo;
import com.tengfei.main.course.domain.bo.ChapterVideoBo;
import com.tengfei.main.course.domain.bo.VideoQuBo;
import com.tengfei.main.course.domain.vo.*;
import com.tengfei.main.course.mapper.*;
import com.tengfei.main.course.service.IChapterService;
import com.tengfei.main.question.domain.Objective;
import com.tengfei.main.question.domain.vo.ObjectiveVo;
import com.tengfei.main.question.mapper.ObjectiveMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 章节Service业务层处理
 *
 * @author tengfei
 * @date 2022-07-27
 */
@Service
public class ChapterServiceImpl implements IChapterService {

    @Resource
    private ChapterMapper baseMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private ChapterVideoMapper chapterVideoMapper;
    @Resource
    private ChapterResMapper chapterResMapper;
    @Resource
    private VideoMapper videoMapper;
    @Resource
    private ResMapper resMapper;
    @Resource
    private ObjectiveMapper objectiveMapper;


    /**
     * 查询章节
     */
    @Override
    public ChapterVo queryById(Long chapterId) {
        ChapterVo chapterVo = baseMapper.selectVoById(chapterId);
        if (ObjectUtil.isNotNull(chapterVo.getCourseId())) {
            Course course = courseMapper.selectById(chapterVo.getCourseId());
            chapterVo.setCourseTitle(course.getCourseTitle());
        }
        return chapterVo;
    }

    /**
     * 查询章节简易信息
     */
    @Override
    public List<Map<String, Object>> querySimplePageList(Long courseId) {
        if (ObjectUtil.isNull(courseId)) {
            throw new ServiceException("课程id为空");
        }
        List<Chapter> chapters = baseMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId)
                .orderByAsc(Chapter::getChapterLevel));
        List<Map<String, Object>> list = new ArrayList<>();

        chapters.forEach(chapter -> {
            Map<String, Object> map = new HashMap<>(2);
            map.put("chapterId", chapter.getChapterId());
            map.put("chapterName", chapter.getChapterName());
            list.add(map);
        });
        return list;
    }

    /**
     * 查询章节列表
     */
    @Override
    public TableDataInfo<ChapterVo> queryPageList(Long courseId, PageQuery pageQuery) {
        if (ObjectUtil.isNull(courseId)) {
            throw new ServiceException("课程id为空");
        }
        IPage<ChapterVo> chapterVoIPage = baseMapper.selectVoPage(pageQuery.build(), new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId)
                .orderByAsc(Chapter::getChapterLevel));
        return TableDataInfo.build(chapterVoIPage);
    }

    /**
     * 查询章节列表
     */
    @Override
    public List<ChapterVo> queryList(ChapterBo bo) {
        LambdaQueryWrapper<Chapter> lqw = buildQueryWrapper(bo);
        List<ChapterVo> chapterVos = baseMapper.selectVoList(lqw);
        chapterVos.forEach(i -> {
            if (ObjectUtil.isNotNull(i.getCourseId())) {
                Course course = courseMapper.selectById(i.getCourseId());
                i.setCourseTitle(course.getCourseTitle());
            }
        });
        return chapterVos;
    }

    private LambdaQueryWrapper<Chapter> buildQueryWrapper(ChapterBo bo) {
        LambdaQueryWrapper<Chapter> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getChapterId() != null, Chapter::getChapterId, bo.getChapterId());
        lqw.like(StringUtils.isNotBlank(bo.getChapterName()), Chapter::getChapterName, bo.getChapterName());
        lqw.eq(bo.getCourseId() != null, Chapter::getCourseId, bo.getCourseId());
        return lqw;
    }

    /**
     * 新增章节
     */
    @Transactional
    @Override
    public Boolean insertByBo(ChapterBo bo) {
        if (ObjectUtil.isNull(bo.getCourseId())) {
            throw new ServiceException("课程id为空");
        }
        Chapter add = BeanUtil.toBean(bo, Chapter.class);
        // 查询章节对应课程
        Course course = courseMapper.selectById(bo.getCourseId());
        if (ObjectUtil.isNull(course)) {
            throw new ServiceException("章节无课程依托");
        }
        // 推断章节排序
        Chapter lastOne = baseMapper.selectOne(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, bo.getCourseId())
                .orderByDesc(Chapter::getChapterLevel)
                .last("limit 1"));
        if (ObjectUtil.isNull(lastOne)) {
            add.setChapterLevel(1);
        } else {
            add.setChapterLevel(lastOne.getChapterLevel() + 1);
        }
        // 课程章节数加一
        course.setCourseChapterCount(course.getCourseChapterCount() + 1);
        courseMapper.updateById(course);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setChapterId(add.getChapterId());
        }
        return flag;
    }

    /**
     * 修改章节
     */
    @Override
    public Boolean updateByBo(ChapterBo bo) {
        if (ObjectUtil.isNull(bo.getChapterId())) {
            throw new ServiceException("章节id不能为空");
        }
        return baseMapper.update(null, new LambdaUpdateWrapper<Chapter>()
                .set(Chapter::getChapterName, bo.getChapterName())
                .eq(Chapter::getChapterId, bo.getChapterId())) > 0;
    }

    /**
     * 批量删除章节
     */
    @Transactional
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        // 该id属于同一视频下的章节，抽取一个判断
        AtomicBoolean isTry = new AtomicBoolean(false);
        ids.forEach(id -> {
            if (!isTry.get()) {
                Chapter chapter = baseMapper.selectById(id);
                if (ObjectUtil.isNotNull(chapter)) {
                    Course course = courseMapper.selectById(chapter.getCourseId());
                    if (course.getCourseIsBegin() == 1) {
                        // 正在开课，无法删除章节
                        throw new ServiceException("所属课程开课中，无法删除章节");
                    }
                    // 修改课程章节数目
                    course.setCourseChapterCount(course.getCourseChapterCount() - ids.size());
                    courseMapper.updateById(course);
                    isTry.set(true);
                }
            }
            // 删除章节对应视频
            chapterVideoMapper.delete(new QueryWrapper<ChapterVideo>().eq("chapter_id", id));
            //删除章节对应的资源
            chapterResMapper.delete(new QueryWrapper<ChapterRes>().eq("chapter_id", id));
        });
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 批量新增章节视频
     *
     * @param bos
     * @return
     */
    @Transactional
    @Override
    public Boolean addVideo(List<ChapterVideoBo> bos) {
        bos.forEach(bo -> {
            ChapterVideo chapterVideo = BeanUtil.copyProperties(bo, ChapterVideo.class);
//            chapterVideo.setProblems(bo.getProblems());
            // 推断排序等级
            // 因为事务的一致性与隔离性，在同一个事务内部，增删改查都是实时响应的
            ChapterVideo lastOne = chapterVideoMapper.selectOne(new LambdaQueryWrapper<ChapterVideo>()
                    .eq(ChapterVideo::getChapterId, chapterVideo.getChapterId())
                    .orderByDesc(ChapterVideo::getLevel)
                    .last("limit 1"));
            if (ObjectUtil.isNotNull(lastOne)) {
                // level加一
                chapterVideo.setLevel(lastOne.getLevel() + 1);
            } else {
                chapterVideo.setLevel(1);
            }
            chapterVideoMapper.insert(chapterVideo);
        });
        // 修改章节视频数目
        Long chapterId = bos.get(0).getChapterId();
        baseMapper.update(null, new LambdaUpdateWrapper<Chapter>()
                .setSql("`chapter_video_count`=`chapter_video_count`+" + bos.size())
                .eq(Chapter::getChapterId, chapterId));
        return true;
    }

    /**
     * 删除章节视频
     *
     * @param ids
     * @return
     */
    @Transactional
    @Override
    public Boolean deleteVideoByChapterIds(List<Long> ids) {
        // 默认为删除同一个章节的视频
        AtomicBoolean isTry = new AtomicBoolean(false);
        ids.forEach(id -> {
            if (!isTry.get()) {
                Long count = chapterVideoMapper.selectCount(new QueryWrapper<ChapterVideo>()
                        .eq("id", id));
                if (count.intValue() - ids.size() <= 1) {
                    throw new ServiceException("章节最低视频数为一");
                }
                isTry.set(true);
            }
            chapterVideoMapper.deleteById(id);
        });
        // 修改章节视频数目
        Long chapterId = chapterVideoMapper.selectOne(new QueryWrapper<ChapterVideo>()
                .eq("id", ids.get(0)))
                .getChapterId();
        baseMapper.update(null, new UpdateWrapper<Chapter>()
                .eq("chapter_id", chapterId)
                .setSql("`chapter_video_count`=`chapter_video_count`-" + ids.size()));
        return true;
    }

    /**
     * 修改章节视频
     *
     * @param bo
     * @return
     */
    @Transactional
    @Override
    public int editVideo(ChapterVideoBo bo) {
        // 更新视频信息
        videoMapper.update(null, new LambdaUpdateWrapper<Video>()
                .set(ObjectUtil.isNotNull(bo.getVideoName()), Video::getVideoName, bo.getVideoName())
                .set(ObjectUtil.isNotNull(bo.getVideoCover()), Video::getVideoCover, bo.getVideoCover())
                .eq(Video::getVideoId, bo.getVideoId()));
        // 更新章节视频信息
        return chapterVideoMapper.update(null, new LambdaUpdateWrapper<ChapterVideo>()
                .set(ObjectUtil.isNotNull(bo.getIsForward()), ChapterVideo::getIsForward, bo.getIsForward())
                .set(ObjectUtil.isNotNull(bo.getProblems()), ChapterVideo::getProblems, bo.getProblems())
                .eq(ChapterVideo::getVideoId, bo.getVideoId())
                .eq(ChapterVideo::getChapterId, bo.getChapterId()));
    }

    /**
     * 章节视频列表
     *
     * @param chapterId
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<ChapterVideoVo> queryVideoList(Long chapterId, PageQuery pageQuery) {
        IPage<ChapterVideo> chapterVideoIPage = chapterVideoMapper.selectPage(pageQuery.build(), new LambdaQueryWrapper<ChapterVideo>()
                .eq(ChapterVideo::getChapterId, chapterId)
                .orderByAsc(ChapterVideo::getLevel));
        Page<ChapterVideoVo> videoVoPage = new Page<ChapterVideoVo>()
                .setCurrent(chapterVideoIPage.getCurrent())
                .setTotal(chapterVideoIPage.getTotal())
                .setSize(chapterVideoIPage.getSize());
        List<ChapterVideoVo> videoVos = new ArrayList<>();
        chapterVideoIPage.getRecords().forEach(chapterVideo -> {
            ChapterVideoVo chapterVideoVo = new ChapterVideoVo();
            // 通过videoId查询视频
            VideoVo videoVo = videoMapper.selectVoById(chapterVideo.getVideoId());
            chapterVideoVo.setId(chapterVideo.getId());
            chapterVideoVo.setVideo(videoVo);
            chapterVideoVo.setIsForward(chapterVideo.getIsForward());
            chapterVideoVo.setProblems(chapterVideo.getProblems());
            videoVos.add(chapterVideoVo);
        });
        videoVoPage.setRecords(videoVos);
        return TableDataInfo.build(videoVoPage);
    }

    /**
     * 查询章节视频
     *
     * @param chapterId
     * @param videoId
     * @return
     */
    @Override
    public ChapterVideoVo queryVideo(Long chapterId, Long videoId) {
        ChapterVideo chapterVideo = chapterVideoMapper.selectOne(new LambdaQueryWrapper<ChapterVideo>()
                .eq(ChapterVideo::getChapterId, chapterId)
                .eq(ChapterVideo::getVideoId, videoId));
        ChapterVideoVo chapterVideoVo = new ChapterVideoVo();
        // 通过videoId查询视频
        VideoVo videoVo = videoMapper.selectVoById(videoId);
        chapterVideoVo.setVideo(videoVo);
        chapterVideoVo.setIsForward(chapterVideo.getIsForward());
        chapterVideoVo.setProblems(chapterVideo.getProblems());
        return chapterVideoVo;
    }

    /**
     * 查询章节视频已绑定题目列表
     */
    @Override
    public List<VideoQuVo> queryVideoBindQuList(Long id) {
        String problems = chapterVideoMapper.selectById(id).getProblems();
        if (ObjectUtil.isNotNull(problems)) {
            List<VideoQu> jsonQus = JsonUtils.parseArray(problems, VideoQu.class);
            List<VideoQuVo> videoObjectiveVos = new ArrayList<>();
            jsonQus.forEach(jsonQu -> {
                Long objId = jsonQu.getObjId();
                // 查询题目详细信息
                ObjectiveVo objectiveVo = objectiveMapper.selectVoById(objId);
                VideoQuVo videoObjectiveVo = BeanUtil.copyProperties(objectiveVo, VideoQuVo.class);
                videoObjectiveVo.setSecond(jsonQu.getPoint());
                videoObjectiveVos.add(videoObjectiveVo);
            });
            return videoObjectiveVos;
        } else {
            return null;
        }
    }

    /**
     * 章节视频解绑题目
     */
    @Override
    public boolean videoDelQu(Long id, Long objId) {
        ChapterVideo chapterVideo = chapterVideoMapper.selectById(id);
        if (ObjectUtil.isNotNull(chapterVideo.getProblems())) {
            List<VideoQu> videoQus = JsonUtils.parseArray(chapterVideo.getProblems(), VideoQu.class);
            for (VideoQu videoQu : videoQus) {
                if (videoQu.getObjId().equals(objId)) {
                    videoQus.remove(videoQu);
                    break;
                }
            }
            if (videoQus.size() > 0) {
                chapterVideo.setProblems(JsonUtils.toJsonString(videoQus));
            }
            boolean res = chapterVideoMapper.updateById(chapterVideo) > 0;
            if (!res) {
                return false;
            }
        }
        return true;
    }

    /**
     * 查询章节视频未绑定题目列表
     */
    @Override
    public TableDataInfo<ObjectiveVo> queryVideoUnBindQuList(VideoQuBo bo, PageQuery pageQuery) {
        // 查询已绑定的题目id列表
        String problems = chapterVideoMapper.selectById(bo.getId()).getProblems();
        List<Long> objIds = ObjectUtil.isNotNull(problems) ? JsonUtils.parseArray(problems, VideoQu.class)
                .stream()
                .map(jsonQu -> jsonQu.getObjId())
                .collect(Collectors.toList()) : null;
        // 查询未绑定题目列表
        Page<ObjectiveVo> objectiveVoPage = objectiveMapper.selectVoPage(pageQuery.build(), new LambdaQueryWrapper<Objective>()
                .notIn(ObjectUtil.isNotNull(objIds) && objIds.size() > 0, Objective::getObjId, objIds)
                .eq(ObjectUtil.isNotNull(bo.getQuType()), Objective::getObjType, bo.getQuType())
                .eq(ObjectUtil.isNotNull(bo.getQuGrand()), Objective::getObjGrand, bo.getQuGrand())
                .like(ObjectUtil.isNotNull(bo.getSearchValue()), Objective::getObjContent, bo.getSearchValue())
                .or()
                .like(ObjectUtil.isNotNull(bo.getSearchValue()), Objective::getObjTag, bo.getSearchValue())
                .orderByDesc(Objective::getUpdateTime));
        return TableDataInfo.build(objectiveVoPage);
    }

    /**
     * 章节视频绑定题目
     */
    @Override
    public boolean videoAddQu(Long id, Long objId, Integer second) {
        ChapterVideo chapterVideo = chapterVideoMapper.selectById(id);
        List<VideoQu> videoQus = ObjectUtil.isNotNull(chapterVideo.getProblems()) ?
                JsonUtils.parseArray(chapterVideo.getProblems(), VideoQu.class) : new ArrayList<>();
        // 是否存在秒数相同
        boolean sameS = false;
        for (VideoQu qus : videoQus) {
            if (qus.getPoint().equals(second)) {
                qus.setObjId(objId);
                sameS = true;
                break;
            }
        }
        // 不存在同时间的
        if (!sameS) {
            VideoQu videoQu = new VideoQu();
            videoQu.setPoint(second);
            videoQu.setObjId(objId);
            videoQus.add(videoQu);
            // list重新排序
            Collections.sort(videoQus, (qu1, qu2) -> qu1.getPoint() - qu2.getPoint());
        }
        chapterVideo.setProblems(JsonUtils.toJsonString(videoQus));
        boolean res = chapterVideoMapper.updateById(chapterVideo) > 0;
        return res;
    }


    /**
     * 修改章节资源
     *
     * @param resId
     * @return
     */
    @Override
    public ResVo queryResById(Long resId) {
        ResVo resVo = resMapper.selectVoById(resId);
        return resVo;
    }

    /**
     * 批量添加章节资源
     *
     * @param bos
     * @return
     */
    @Transactional
    @Override
    public Boolean addRes(List<ChapterResBo> bos) {
        // 推断资源排序
        bos.forEach(bo -> {
            ChapterRes chapterRes = BeanUtil.copyProperties(bo, ChapterRes.class);
            ChapterRes lastOne = chapterResMapper.selectOne(new LambdaQueryWrapper<ChapterRes>()
                    .eq(ChapterRes::getChapterId, bo.getChapterId())
                    .orderByDesc(ChapterRes::getLevel)
                    .last("limit 1"));
            if (ObjectUtil.isNotNull(lastOne)) {
                chapterRes.setLevel(lastOne.getLevel() + 1);
            } else {
                chapterRes.setLevel(1);
            }
            chapterResMapper.insert(chapterRes);
        });
        return true;
    }

    /**
     * 修改章节资源
     *
     * @param resId
     * @param resName
     * @return
     */
    @Override
    public int editRes(Long resId, String resName) {
        Res res = new Res();
        res.setResId(resId);
        res.setResName(resName);
        return resMapper.updateById(res);
    }

    /**
     * 删除章节资源
     *
     * @param ids
     * @return
     */
    @Transactional
    @Override
    public Boolean deleteResByChapterIds(List<Long> ids) {
        return chapterResMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 获取章节资源列表
     *
     * @param chapterId
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<ResVo> queryResList(Long chapterId, PageQuery pageQuery) {
        Page<ChapterRes> videoIPage = chapterResMapper.selectPage(pageQuery.build(), new LambdaQueryWrapper<ChapterRes>()
                .eq(ChapterRes::getChapterId, chapterId)
                .orderByAsc(ChapterRes::getLevel));
        Page<ResVo> resVoPage = new Page<ResVo>()
                .setSize(videoIPage.getSize())
                .setCurrent(videoIPage.getCurrent())
                .setTotal(videoIPage.getTotal());
        List<ResVo> resVos = new ArrayList<>();
        videoIPage.getRecords().forEach(i -> {
            // 获取资源详细信息
            ResVo resVo = resMapper.selectVoById(i.getResId());
            resVos.add(resVo);
        });
        return TableDataInfo.build(resVos);
    }


}
